% Ejercicio "Formulación química"
\subsection*{\fbox{\theejercicio} - Formulaci\'on qu\'{\i}mica}

En Qu\'{\i}mica Inorg\'anica se utiliza un lenguaje formal para expresar las f\'ormulas de los compuestos. Cada f\'ormula describe la composici\'on de una mol\'ecula, que se obtiene por la combinaci\'on de uno o m\'as \'atomos, o un grupo de \'estosformando lo que se conoce por iones.

\smallskip

As\'{\i}, por ejemplo, la mol\'ecula del agua se escribe H$_2$O, indicando que est\'a compuesta por dos \'atomos de hidrogeno y uno de ox\'{\i}geno. Algo mas complicadas son las f\'ormulas del bicarbonato s\'odico: NaHCO$_3$, del sulfato f\'errico: Fe$_2$(SO$_4$)$_3$, o del ferrocianuro f\'errrico Fe$_2$(Fe(CN)$_3$)$_3$ en la que los par\'entesis se utilizan para indicar que un grupo de \'atomos forma un i\'on, y los sub\'{\i}ndices exteriores indican el n\'umero de iones que entran a formar parte de la mol\'ecula.

\smallskip

Los s\'{\i}mbolos qu\'{\i}micos correspondientes a los \'atomos se representan mediante su s\'{\i}mbolo qu\'{\i}mico formado
por una o dos letras, la primera de las cuales es siempre mayuscula. (por ejemplo:  carbono: C,  nitr\'ogeno: N, hierro: Fe,
sodio: Na).

\smallskip

Cada \'atomo est\'a caracterizado, adem\'as de por su s\'{\i}mbolo qu\'{\i}mico, por un peso at\'omico, que puede representarse por un n\'umero entero positivo (hidr\'ogeno: 1, carbono: 12, oxigeno: 16, hierrro: 56) y por una o varias valencias, aunque  {\bf para el problema que nos ocupa consideraremos que un \'atomo solo puede actuar con una \'unica valencia}. Las valencias pueden ser positivas o negativas y su valor es un entero (carbono: -4, oxigeno: -2, hierro: +3).

\smallskip

Construir mediante LEX y YACC un programa capaz de ``entender'' una f\'ormula inorg\'anica, comprobar que es una f\'ormula correcta y calcular su peso molecular, comprobar que est\'a bien formulada desde el punto de vista de las valencias con las que actuan los \'atomos, es decir, que la suma total de las cargas positivas y negativas de todos los \'atomos que integran la mol\'ecula es cero. (equilibrio i\'onico). As\'{\i} por ejemplo, la mol\'ecula del agua tiene un peso molecular de 18 y est\'a en equilibrio i\'onico ya que las dos valencias negativas del ox\'{\i}geno se compensan con cada una de las valencias positivas de los dos \'atomos de hidr\'ogeno.

\smallskip

Para realizar esta tarea es necesario previamente dise\~nar las fases de an\'alisis lexicogr\'afico y sint\'actico, estableciendo los tokens y la gram\'atica correspondiente al analizador sint\'actico del lenguaje utilizado para la formulaci\'on en qu\'{\i}mica inorg\'anica. Para ello supondremos que las f\'ormulas se escriben en un fichero de texto en el que no se incluyen caracteres de control especiales para los sub\'{\i}ndices, es decir, la f\'ormula del sulfato f\'errico aparecer\'{\i}a en el fichero como: \verb@Fe2(SO4)3@. Por simplicidad supondremos que s\'olo hay una f\'ormula en cada fichero.

\smallskip

El sistema dispone de una tabla en la que est\'a almacenado el nombre del s\'{\i}mbolo qu\'{\i}mico, su peso at\'omico, y la valencia con que act\'ua en una molecula; para cada uno de los 105 elementos qu\'{\i}micos existentes. Asimismo, se ha definido una funci\'on capaz de localizar un elemento en esta tabla. La implementaci\'on se ha realizado mediante las siguientes definiciones en C:

\begin{verbatim}
typedef struct tabla
{
   char simbolo[2];
   int paso;
   int valencia;
} tabla;

tabla tablaperiodica[105];
tabla *buscar(char *simb); /* devuelve un puntero a la posicion en
                              la tabla del simbolo simb, o NULL en
                              caso de que no exista este simbolo */
\end{verbatim}

% Solución del ejercicio
\subsubsection*{SOLUCI\'ON}

\underline{ESPECIFICACI\'ON LEX}:

\begin{verbatim}
%{
#include "y.tab.h" 
#include "tablasim.h" 
%}

%%
[A-Z][a-z]?      {
                   tabla *s;
                   s = buscar((char*)yytext);
                   if (s != NULL) {
                      yylval.atr.p = s->peso;
                      yylval.atr.v = s->valencia;
                      return ELEMENTO;
                   }
                   else fprintf(stderr,"Error en la entrada\n"); 
                 }
[0-9]+           {
                   yylval.val = atoi(yytext);
                   return N;
                 }
\(               { return `('; }
\)               { return `)'; }
[\ \b\n]+        { ; }
.                {
                   fprintf(stderr,"Caracteres no validos en la entrada
                                  (%s)\n",yytext);
                 }
%%
\end{verbatim}

\underline{ESPECIFICACI\'ON YACC}:

\begin{verbatim}
%{
#include "quimica.h"
%}

%union
 {
     struct {int p,v;} atr;
     int val;
 }

%type   <atr>  compuesto  formula  ion
%type   <val>  numero

%token  <atr>  ELEMENTO
%token  <val>  N

%%
compuesto: formula    {
                        fprintf(yyout,"Peso molecular: %3d\n",$1.p);
                        if ($$.v == 0)
                           fprintf(yyout,"Hay equilibrio ionico\n");
                        else
                           fprintf(yyout,"No hay equilibrio ionico\n");
                      }
       ;

formula:  formula ion numero  { $$.p = $1.p + $2.p*$3; $$.v = $1.v + $2.v*$3; }
       |  ion numero          { $$.p = $1.p*$2;  $$.v = $1.v*$2;}
       ;

ion:       ELEMENTO           { $$.p = $1.p;  $$.v = $1.v; }
       |   `(' formula `)'    { $$.p = $2.p;  $$.v = $2.v; }
       ;

numero:    /* epsilon */      { $$ = 1; }
       |   N                  { $$ = $1; }
       ;

%%
\end{verbatim}

\underline{FICHERO quimica.h}:

\begin{verbatim}
#include <stdio.h>

extern FILE *yyin, *yyout;
int yyerror(char*);
\end{verbatim}

\underline{FICHERO quimica.c}:

\begin{verbatim}
#include "quimica.h"

char *nombreprograma;
int numlinea;

/*******************************************************/
/* yyerror                                             */
/*******************************************************/
yyerror(char *s)
{
  fprintf(stderr,"%s(%d): %s \n",nombreprograma,numlinea,s);
}

/*******************************************************/
/* main                                                */
/*******************************************************/
main (int argc, char *argv[])
{
  void cerrarficheros ();
  int abrirficheros ();
  nombreprograma = argv[0];
  if (abrirficheros (argc, argv))
      yyparse();
  cerrarficheros ();
}

/******************************************************/
/* abrirficheros                                      */
/*   abre los ficheros de entrada y salida            */
/*   devuelve 0 en caso de error                      */
/******************************************************/
abrirficheros (int argc, char *argv[])
{
  if (argc > 3) { printf ("Demasiados parametros.\n"); return (0); }
  if (argc > 1) yyin  = fopen (*(argv+1), "r");
  if (yyin == NULL) { printf ("Fichero no encontrado.\n"); return (0); }
  if (argc > 2) yyout = fopen (*(argv+2), "w");
  return (1);
}

/*******************************************************/
/* cerrarficheros                                      */
/*   cierra los ficheros de entrada y salida           */
/*******************************************************/
void cerrarficheros () { fclose (yyin); fclose (yyout); return; }
\end{verbatim}

\underline{FICHERO tablasim.h}:

\begin{verbatim}
/**************************************************/
/*  Estructura de la tabla de simbolos            */
/**************************************************/
typedef struct tabla
{
  char *id;
  int peso,valencia;
} tabla ;

/**************************************************/
/*  Funciones                                     */
/**************************************************/
tabla *buscar(char *);
void    listartabla();
\end{verbatim}

\underline{FICHERO tablasim.c}:

\begin{verbatim}
#include <string.h>
#include <stdlib.h>
#include "tablasim.h"

tabla  tablaperiodica[] =
    {
      "H",    1,   1,
      "He",   2,   0,
      "Li",   3,   1,

      "C",   12,   4,
      "N",   14,   5,
      "O",   16,  -2,
      "S",   32,   6,
      "Fe",  56,   3,
      "Na",  40,   1,

      0, 0, 0
      }  ;

/**************************************************/
/*  buscar                                        */
/**************************************************/
tabla *buscar(char *simb) 
{
  int i;
  for(i=0; tablaperiodica[i].id != NULL; i++)
     if (strcmp(tablaperiodica[i].id,simb) == 0)
 return &tablaperiodica[i];

  return (tabla*) NULL;
}
\end{verbatim}

\underline{FICHERO Makefile}:

\begin{verbatim}
# Compilador

CC = cc

# Flags

CFLAGS = -Aa

# Ficheros

HDRS = quimica.h \
       tablasim.h

CSRCS = quimica.c \
        tablasim.c

SRCS = $(CSRCS) \
       lex.yy.c \
       y.tab.c

OBJS = quimica.o \
       tablasim.o \
       lex.yy.o \
       y.tab.o

.c.o:
 $(CC) -c $(CFLAGS) $*.c

quimica: $(OBJS)
  $(CC) $(CFLAGS) $(OBJS) -ll -o quimica

# Dependencias de los ficheros C

$(OBJS): $(HDRS)

# Dependencies de los ficheros de LEX y YACC

lex.yy.c: quimica.lex y.tab.h
      lex quimica.lex

y.tab.c y.tab.h: quimica.y
      yacc -d quimica.y

# Borrar todo
borrar:
      rm *.o y.tab.* lex.yy.*
\end{verbatim}